using System;
using System.Collections.Generic;
using UnityEngine;

public class RacketSettings : ScriptableObjectSingleton<RacketSettings>
{
	public enum SettingsType
	{
		SimpleSettings = 0,
		RangeSettings = 1
	}

	[Serializable]
	public class RacketRangeSettings
	{
		public FloatRange fingerSpeedRange = new FloatRange
		{
			min = 2f,
			max = 5f
		};

		public FloatRange zLandingPosRange = new FloatRange
		{
			min = 0.3f,
			max = 0.8f
		};

		public FloatRange ballVelocityRange = new FloatRange
		{
			min = 0.3f,
			max = 0.05f
		};

		public FloatRange heightOverNet = new FloatRange
		{
			min = -3f,
			max = 1f
		};

		public FloatRange downSpin = new FloatRange
		{
			min = 0f,
			max = 0f
		};

		public float normalizedSpinLimit = 0.7f;

		public float forwardSpinLimit = 0.7f;

		public float spin = 5f;

		public float aimZ;

		public float aimXMult = 1f;

		public FloatRange shotPerfectionRange = new FloatRange
		{
			min = 0.01f,
			max = 1f
		};

		public bool useNormalTime = true;

		public bool useLengthForDistance;

		public float minAttackZ;

		public float attackTimeMult = 1f;

		public float airResistance;

		public float rebound = 1f;

		public float tableXRange = 1f;

		public float safetyRange = 1.2f;

		public float GetTimeToLand(float normalizedForwardFingerSpeed, Vector3 landingPos, PhysicsBall ball)
		{
			return GetTimeToLand(normalizedForwardFingerSpeed, landingPos, ball.position);
		}

		public float GetTimeToLand(float normalizedForwardFingerSpeed, Vector3 landingPos, Vector3 ballPos)
		{
			float num = Vector3Ex.HorizontalDistance(landingPos, ballPos);
			if (useLengthForDistance)
			{
				num = Mathf.Abs(landingPos.z - ballPos.z);
			}
			float num2 = Table.length / ballVelocityRange.Lerp(normalizedForwardFingerSpeed);
			return num / num2 * GetAttackMult(ballPos);
		}

		public float GetAttackMult(Ball ball)
		{
			return GetAttackMult(ball.position);
		}

		public float GetAttackMult(Vector3 ballPos)
		{
			return 1f;
		}

		public void HitBall(Racket racket, float forwardSpeed, Vector3 velocity, TableTennisHumanPlayerRacket player, PhysicsBall ball, int neededAreaMarkerHits)
		{
			int tableSide = player.tableSide;
			bool isServe = player.IsInServe();
			Vector3 normalized = velocity.normalized;
			if (Mathf.Abs(normalized.x) <= forwardSpinLimit)
			{
				forwardSpeed = Mathf.Sqrt(velocity.x * velocity.x + velocity.z * velocity.z) / Table.length;
			}
			float num = fingerSpeedRange.InverseLerp(forwardSpeed);
			velocity = normalized;
			float z = (float)(-tableSide) * Table.halfLength * zLandingPosRange.Lerp(num);
			float num2 = (float)(-tableSide) * Table.halfLength * aimZ;
			float num3 = Mathf.Abs(ball.position.z - num2);
			float f = ball.position.x + velocity.x * num3 * aimXMult;
			float spinx = 0f;
			if (Mathf.Abs(velocity.x) > normalizedSpinLimit)
			{
				if (Mathf.Abs(velocity.x) > forwardSpinLimit)
				{
					f = ball.position.x;
					z = (float)(-tableSide) * Table.halfLength * zLandingPosRange.Lerp(num);
					num = 0.5f;
				}
				spinx = (float)tableSide * spin * Mathf.Sign(velocity.x);
			}
			float num4 = Table.halfwidth * safetyRange;
			if (Mathf.Abs(ball.position.x) > Table.halfwidth)
			{
				num4 += Mathf.Abs(ball.position.x) - Table.halfwidth;
			}
			if (Mathf.Abs(f) > Table.halfwidth && Mathf.Abs(f) < num4)
			{
				f = Mathf.Sign(f) * (Table.halfwidth - num4 + Mathf.Abs(f));
			}
			if (Mathf.Abs(f) < Table.halfwidth)
			{
				f = Mathf.Sign(f) * Mathf.Min(Mathf.Abs(f), Table.halfwidth * tableXRange);
			}
			f = Mathf.Min(Mathf.Abs(f), Table.halfwidth * 1.5f) * Mathf.Sign(f);
			Vector3 landingPos = new Vector3(f, Table.tabletopy, z);
			float heightAboveNet = Table.netHeight + heightOverNet.Lerp(num);
			float timeToLand = GetTimeToLand(num, landingPos, ball);
			float spiny = downSpin.Lerp(num);
			player.HitBall(landingPos, heightAboveNet, timeToLand, spinx, spiny, isServe, useNormalTime, airResistance, rebound, racket.timeScale);
		}
	}

	[Serializable]
	public class Racket
	{
		public SettingsType type;

		public List<RacketRangeSettings> ranges = new List<RacketRangeSettings>();

		public RacketRangeSettings super = new RacketRangeSettings();

		public FloatRange fingerSpeedRange = new FloatRange
		{
			min = 2f,
			max = 5f
		};

		public FloatRange zLandingPosRange = new FloatRange
		{
			min = 0.3f,
			max = 0.8f
		};

		public FloatRange ballVelocityRange = new FloatRange
		{
			min = 0.3f,
			max = 0.05f
		};

		public FloatRange heightOverNet = new FloatRange
		{
			min = -3f,
			max = 1f
		};

		public FloatRange downSpin = new FloatRange
		{
			min = 0f,
			max = 0f
		};

		public float normalizedSpinLimit = 0.7f;

		public float spin = 5f;

		public int areaMarkerHits = 1;

		public float timeScale = 0.75f;

		public float paddleWidth = 0.4f;

		public void HitBall(TableTennisHumanPlayerRacket player, PhysicsBall ball)
		{
			if (type == SettingsType.SimpleSettings)
			{
				HitBallSimple(player, ball);
			}
			else
			{
				HitBallRange(player, ball);
			}
		}

		public void HitBallSimple(TableTennisHumanPlayerRacket player, PhysicsBall ball)
		{
			int tableSide = player.tableSide;
			bool isServe = player.IsInServe();
			Vector3 vector = player.CalculateVelocityFromGestureTracker();
			if (Mathf.Sign(vector.z) != (float)tableSide)
			{
				vector.z *= -1f;
			}
			Vector3 vector2 = vector;
			vector.Normalize();
			float value = fingerSpeedRange.InverseLerp(Mathf.Abs(vector2.z / Table.length));
			float num = (float)(-tableSide) * Table.halfLength * zLandingPosRange.Lerp(value);
			float num2 = Mathf.Abs(ball.position.z - num);
			float num3 = ball.position.x + vector.x * num2;
			float spinx = 0f;
			if (Mathf.Abs(vector.x) > normalizedSpinLimit)
			{
				num3 = ball.position.x;
				spinx = (float)tableSide * spin * Mathf.Sign(vector.x);
				num = (float)(-tableSide) * Table.halfLength * zLandingPosRange.Lerp(value);
				value = 0.5f;
			}
			float num4 = Table.width * 0.35f;
			if (Mathf.Abs(ball.position.x) > Table.halfwidth)
			{
				num4 += Mathf.Abs(ball.position.x) - Table.halfwidth;
			}
			if (Mathf.Abs(num3) > Table.halfwidth)
			{
				num3 += (0f - Mathf.Sign(num3)) * Mathf.Min(num4, Mathf.Abs(num3) - Table.halfwidth * 0.9f);
			}
			Vector3 vector3 = new Vector3(num3, Table.tabletopy, num);
			float heightAboveNet = Table.netHeight + heightOverNet.Lerp(value);
			float num5 = Vector3Ex.HorizontalDistance(vector3, ball.position);
			float timeToLand = ballVelocityRange.Lerp(value);
			float spiny = downSpin.Lerp(value);
			if (player.markerHits > 0)
			{
				spiny = downSpin.max * 2f;
				heightAboveNet = heightOverNet.Lerp(0.5f);
			}
			player.HitBall(vector3, heightAboveNet, timeToLand, spinx, spiny, isServe);
			if (player.markerHits > 0)
			{
				player.markerHits = 0;
				player.match.ui.ballFollower.fire.SetActive(true);
			}
		}

		public RacketRangeSettings GetSettingsForRange(float forwardSpeed)
		{
			RacketRangeSettings result = null;
			foreach (RacketRangeSettings range in ranges)
			{
				result = range;
				if (forwardSpeed <= range.fingerSpeedRange.max)
				{
					break;
				}
			}
			return result;
		}

		public void HitBallRange(TableTennisHumanPlayerRacket player, PhysicsBall ball)
		{
			int tableSide = player.tableSide;
			bool flag = player.IsInServe();
			Vector3 vector = player.CalculateVelocityFromGestureTracker();
			Vector3 velocity = vector;
			vector.Normalize();
			if (Mathf.Sign(vector.z) == (float)tableSide)
			{
				vector.z *= -1f;
			}
			float forwardSpeed = (float)(-tableSide) * velocity.z / Table.length;
			RacketRangeSettings settingsForRange = GetSettingsForRange(forwardSpeed);
			if (player.markerHits >= areaMarkerHits)
			{
				settingsForRange = super;
			}
			settingsForRange.HitBall(this, forwardSpeed, velocity, player, ball, areaMarkerHits);
			if (player.markerHits >= areaMarkerHits)
			{
				player.markerHits = 0;
				player.match.ui.ballFollower.fire.SetActive(true);
			}
		}
	}

	public List<Racket> rackets = new List<Racket>();
}
